/*
 * Copyright 2009 Jamie Gennis
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.gwt.dev.javac;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.Name.BinaryName;

/**
 * A class for building a TypeOracle for use in testing.
 * 
 * @author jgennis
 */
public class TypeOracleBuilder {

  // protected static final TreeLogger logger = new PrintWriterTreeLogger();
  protected static final TreeLogger logger = TreeLogger.NULL;

  protected final Set<Resource> resources = new HashSet<Resource>();

  public TypeOracleBuilder() {
    addStandardClasses();
  }

  public boolean add(Class<?> clazz) {
    String className = clazz.getCanonicalName();
    return add(className);
  }

  public boolean add(Resource compilationUnit) {
    return resources.add(compilationUnit);
  }

  public TypeOracle buildTypeOracle() {
    CompilationState cs = CompilationStateBuilder.buildFrom(logger, resources);
    return cs.getTypeOracle();
  }

  protected boolean add(String className) {
    String internalName = BinaryName.toInternalName(className);
    if (className.startsWith("java.")) {
      internalName = "com/google/gwt/emul/" + internalName;
    }
    return add(className, internalName);
  }

  protected boolean add(String className, String internalName) {
    ClassLoader classLoader = getClass().getClassLoader();
    String fileName = internalName + ".java";
    InputStream sourceStream = classLoader.getResourceAsStream(fileName);
    BufferedReader sourceReader = new BufferedReader(new InputStreamReader(sourceStream));
    StringBuffer code = new StringBuffer();
    String line;
    try {
      while ((line = sourceReader.readLine()) != null)
        code.append(line + "\n");
    } catch (IOException ex) {
      throw new RuntimeException(ex);
    }
    String path = BinaryName.toInternalName(className) + ".java";
    MockResource mr = new MockResource(path, code.toString());
    return resources.add(mr);
  }

  protected void addStandardClasses() {
    // Java classes
    add("java.io.FilterOutputStream");
    add("java.io.IOException");
    add("java.io.OutputStream");
    add("java.io.PrintStream");
    add("java.io.Serializable");
    // add("java.lang.annotation.Annotation");
    // add("java.lang.annotation.AnnotationFormatError");
    // add("java.lang.annotation.AnnotationTypeMismatchException");
    // add("java.lang.annotation.Documented");
    // add("java.lang.annotation.ElementType");
    // add("java.lang.annotation.IncompleteAnnotationException");
    // add("java.lang.annotation.Inherited");
    // add("java.lang.annotation.Retention");
    // add("java.lang.annotation.RetentionPolicy");
    // add("java.lang.annotation.Target");
    add("java.lang.Appendable");
    // add("java.lang.ArithmeticException");
    // add("java.lang.ArrayIndexOutOfBoundsException");
    add("java.lang.ArrayStoreException");
    // add("java.lang.AssertionError");
    add("java.lang.Boolean");
    add("java.lang.Byte");
    add("java.lang.Character");
    add("java.lang.CharSequence");
    add("java.lang.ClassCastException");
    add("java.lang.Class");
    add("java.lang.Cloneable");
    add("java.lang.Comparable");
    // add("java.lang.Deprecated");
    add("java.lang.Double");
    add("java.lang.Enum");
    add("java.lang.Error");
    add("java.lang.Exception");
    add("java.lang.Float");
    add("java.lang.IllegalArgumentException");
    add("java.lang.IllegalStateException");
    add("java.lang.IndexOutOfBoundsException");
    add("java.lang.Integer");
    add("java.lang.Iterable");
    add("java.lang.Long");
    add("java.lang.Math");
    // add("java.lang.NegativeArraySizeException");
    add("java.lang.NullPointerException");
    add("java.lang.Number");
    add("java.lang.NumberFormatException");
    add("java.lang.Object");
    // add("java.lang.Override");
    // add("java.lang.Runnable");
    add("java.lang.RuntimeException");
    add("java.lang.Short");
    add("java.lang.StackTraceElement");
    add("java.lang.StringBuffer");
    add("java.lang.StringBuilder");
    add("java.lang.String");
    add("java.lang.StringIndexOutOfBoundsException");
    // add("java.lang.SuppressWarnings");
    add("java.lang.System");
    add("java.lang.Throwable");
    add("java.lang.UnsupportedOperationException");
    add("java.lang.Void");
    // add("java.sql.Date");
    // add("java.sql.Time");
    // add("java.sql.Timestamp");
    add("java.util.AbstractCollection");
    add("java.util.AbstractHashMap");
    add("java.util.AbstractList");
    add("java.util.AbstractMap");
    add("java.util.AbstractMapEntry");
    // add("java.util.AbstractQueue");
    add("java.util.AbstractSequentialList");
    add("java.util.AbstractSet");
    add("java.util.ArrayList");
    // add("java.util.Arrays");
    add("java.util.Collection");
    // add("java.util.Collections");
    add("java.util.Comparator");
    // add("java.util.Comparators");
    // add("java.util.ConcurrentModificationException");
    // add("java.util.Date");
    // add("java.util.EmptyStackException");
    // add("java.util.Enumeration");
    // add("java.util.EnumMap");
    // add("java.util.EnumSet");
    // add("java.util.EventListener");
    // add("java.util.EventObject");
    add("java.util.HashMap");
    // add("java.util.HashSet");
    // add("java.util.IdentityHashMap");
    add("java.util.Iterator");
    // add("java.util.LinkedHashMap");
    // add("java.util.LinkedHashSet");
    add("java.util.LinkedList");
    add("java.util.List");
    add("java.util.ListIterator");
    add("java.util.Map");
    add("java.util.MapEntryImpl");
    // add("java.util.MissingResourceException");
    add("java.util.NoSuchElementException");
    // add("java.util.PriorityQueue");
    add("java.util.Queue");
    add("java.util.RandomAccess");
    add("java.util.Set");
    // add("java.util.SortedMap");
    // add("java.util.SortedSet");
    // add("java.util.Stack");
    // add("java.util.TooManyListenersException");
    // add("java.util.TreeMap");
    // add("java.util.TreeSet");
    add("java.util.Utility");
    // add("java.util.Vector");

    // GWT classes
    add("com.google.gwt.core.client.Duration");
    add("com.google.gwt.core.client.GWT");
    add("com.google.gwt.core.client.GWTBridge");
    add("com.google.gwt.core.client.JsArray");
    add("com.google.gwt.core.client.JsArrayString");
    add("com.google.gwt.core.client.JavaScriptObject");
    add("com.google.gwt.core.client.JavaScriptException");
    add("com.google.gwt.core.client.RunAsyncCallback");
    add("com.google.gwt.core.client.Scheduler");
    add("com.google.gwt.core.client.impl.AsyncFragmentLoader");
    add("com.google.gwt.core.client.impl.Impl");
    add("com.google.gwt.core.client.impl.SchedulerImpl");
    add("com.google.gwt.core.client.impl.StackTraceCreator");
    add("com.google.gwt.core.client.impl.StringBufferImpl");
    add("com.google.gwt.user.client.rpc.AsyncCallback");
    add("com.google.gwt.user.client.rpc.IsSerializable");
    add("com.google.gwt.xhr.client.XMLHttpRequest");
    add("com.google.gwt.xhr.client.ReadyStateChangeHandler");

    // Intrinsics
    add("com.google.gwt.lang.Array", "com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array");
    add("com.google.gwt.lang.Cast", "com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast");
    add("com.google.gwt.lang.Util", "com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util");
  }
}
